package com.miyake.dsp.osa;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import sun.misc.BASE64Encoder;

public class OsaXml {
	private Document doc = null;
	private OsaSetting osaSetting;
	private List<double[]> traces = null;
	private AnalysisProperty anaProp;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		OsaCsv csvIn  =new OsaCsv("D:\\OSA3\\競争力強化\\東北大学データ\\WaveData20111212_000.csv");
		OsaCsv csvOut  =new OsaCsv("D:\\OSA3\\競争力強化\\東北大学データ\\WaveData20111212_001.csv");

		List<double[]> traces = new ArrayList<double[]>();
		traces.add(csvIn.getLevel());
		traces.add(csvOut.getLevel());
		traces.add(csvOut.getLevel());
		OsaXml xml = new OsaXml(csvIn.getSetting(), null, traces);

		xml.writeXML("D:\\OSA3\\バグ\\sample100.xml");

		byte[] b = Base64.decodeBase64(xml.getTraceBase64(0));
		for (int i = 0; i < b.length / 8; i++) {
			byte[] tmp = new byte[8];
			for (int j = 0; j < 8; j++) {
				tmp[7-j] = b[i * 8 + j];
			}
        	ByteArrayInputStream tmpb = new ByteArrayInputStream(tmp);
        	DataInputStream tmpdd = new DataInputStream(tmpb);
        	try {
				System.out.println(tmpdd.readDouble() + ", " + csvOut.getLevel()[i]);
			} catch (IOException e) {
				e.printStackTrace();
				LogTrace.writeLog(e.toString());
			}
		}

	}

	public OsaXml(OsaSetting setting, AnalysisProperty anaProp, List<double[]> traces) {
		this.osaSetting = setting;
		this.traces = traces;
		readXML("data\\reference.xml", setting, anaProp);
	}

	public void writeXML(String filename) {
		TransformerFactory tfactory = TransformerFactory.newInstance();
        Transformer transformer;
		try {
			transformer = tfactory.newTransformer();
	        File outfile = new File(filename);
	        transformer.transform(new DOMSource(doc), new StreamResult(outfile));

		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
			LogTrace.writeLog(e.toString());
		} catch (TransformerException e) {
			e.printStackTrace();
			LogTrace.writeLog(e.toString());
		}
	}


	private void readXML(String filename, OsaSetting osaSetting, AnalysisProperty anaProp) {
		this.anaProp = anaProp;
		
		try {
			// �ｽh�ｽL�ｽ�ｽ�ｽ�ｽ�ｽ�ｽ�ｽg�ｽr�ｽ�ｽ�ｽ_�ｽ[�ｽt�ｽ@�ｽN�ｽg�ｽ�ｽ�ｽｶ撰ｿｽ
			DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
			// �ｽh�ｽL�ｽ�ｽ�ｽ�ｽ�ｽ�ｽ�ｽg�ｽr�ｽ�ｽ�ｽ_�ｽ[�ｽｶ撰ｿｽ
			DocumentBuilder builder = dbfactory.newDocumentBuilder();
			// �ｽp�ｽ[�ｽX�ｽ�ｽ�ｽ�ｽ�ｽs�ｽ�ｽ�ｽ�ｽDocument�ｽI�ｽu�ｽW�ｽF�ｽN�ｽg�ｽ�ｽ�ｽ謫ｾ
			doc = builder.parse(new BufferedInputStream(new FileInputStream(filename)));

			doc.setXmlStandalone(true);

			// �ｽ�ｽ�ｽ[�ｽg�ｽv�ｽf�ｽ�ｽ�ｽ謫ｾ�ｽi�ｽ^�ｽO�ｽ�ｽ�ｽFmessage�ｽj
			Element root = doc.getDocumentElement();

			NodeList listWave = root.getElementsByTagName("WaveData");
			for (int i = 0; i < listWave.getLength(); i++) {
				Element e = (Element)listWave.item(i);
				e.getChildNodes().item(0).setNodeValue(getTraceBase64(i));
			}

			NodeList listParam = root.getElementsByTagName("Parameters");
			for (int i = 0; i < listParam.getLength(); i++) {
				Element e = (Element)listParam.item(i);
				NodeList n = e.getElementsByTagName("Attribute");
				for (int j = 0; j < n.getLength(); j++) {
					Node n2 = n.item(j);
					NamedNodeMap map = n2.getAttributes();
					for (int k = 0; k < map.getLength(); k++) {
						String s = map.item(k).getTextContent();
						if (s.contains("Center Wavelength")) {
							map.getNamedItem("Value").setTextContent(getCenter());
						}
						else if (s.contains("Span Wavelength")) {
							map.getNamedItem("Value").setTextContent(getSpan());
						}
						else if (s.contains("Start Wavelength")) {
							map.getNamedItem("Value").setTextContent(getStart());
						}
						else if (s.contains("Stop Wavelength")) {
							map.getNamedItem("Value").setTextContent(getStop());
						}
						else if (s.contains("Resolution")) {
							if (!s.contains("Actual Resolution") && !s.contains("Search Resolution")) {
								map.getNamedItem("Value").setTextContent(getSettingRes());
							}
						}
						else if (s.contains("Actual Resolution")) {
							if (!s.equals("Actual Resolution On/Off")) {
								map.getNamedItem("Value").setTextContent(getActualRes());
							}
						}
						else if (s.contains("Sampling Points")) {
							map.getNamedItem("Value").setTextContent(getSamplingPoints());
						}
						
						else if (s.contains("Value In Air/Vacuum")) {
							map.getNamedItem("Value").setTextContent(getAirVacuum());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Method")) {
							map.getNamedItem("Value").setTextContent(getMethod());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Detection Type")) {
							map.getNamedItem("Value").setTextContent(getAseDetectionType());
						}	
						else if (s.contains("Opt.Amp(Multi Channel) Noise Position Mode")) {
							map.getNamedItem("Value").setTextContent(getNoisePositionMode());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Noise Position")) {
							if (!s.contains("Mode")) {
								map.getNamedItem("Value").setTextContent(getNoisePosition());
							}
						}
						else if (s.contains("Opt.Amp(Multi Channel) Fitting Span Mode")) {
							map.getNamedItem("Value").setTextContent(getFittingSpanMode());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Fitting Span")) {
							if (!s.contains("Mode")) {
								map.getNamedItem("Value").setTextContent(getFittingSpan());
							}
						}
						else if (s.contains("Opt.Amp(Multi Channel) Masked Span")) {
							map.getNamedItem("Value").setTextContent(getMaskedSpan());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Fitting Curve")) {
							map.getNamedItem("Value").setTextContent(getFittingCurve());
						}
						else if (s.contains("Opt.Amp(Multi Channel) NF Select")) {
							map.getNamedItem("Value").setTextContent(getNfSelect());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Actual Resolution")) {
							map.getNamedItem("Value").setTextContent(getActualResolutionMethod());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Slice Level")) {
							map.getNamedItem("Value").setTextContent(getSliceLevel());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Search Threshold")) {
							map.getNamedItem("Value").setTextContent(getSearchThreshold());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Wl Detection Type")) {
							map.getNamedItem("Value").setTextContent(getWavelengthDetectionType());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Peak Threshold Cut Level")) {
							map.getNamedItem("Value").setTextContent(getCutLevel());
						}
						else if (s.contains("Opt.Amp(Multi Channel) NF Calibration")) {
							map.getNamedItem("Value").setTextContent(getNfCal());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Pin Loss")) {
							map.getNamedItem("Value").setTextContent(getPinLoss());
						}
						else if (s.contains("Opt.Amp(Multi Channel) Pout Loss")) {
							map.getNamedItem("Value").setTextContent(getPoutLoss());
						}
					}
					//System.out.println(n2.get);
					//System.out.println(n.item(j).getNodeName());
				}
				//(NodeList)(e).getElementsByTagName("Trace");
				//e.getChildNodes().item(0).setNodeValue(getTraceBase64(i));
			}
//			NodeList list2 = (NodeList)((Element)list.item(0)).getElementsByTagName("Trace");
//			NodeList list3 = (NodeList)((Element)list2.item(0)).getElementsByTagName("TraceIndex");
//			NodeList list4 = (NodeList)((Element)list3.item(0)).getElementsByTagName("WaveData");

//			NodeList list2 = (e).getElementsByTagName("WaveData");
			//System.out.println(list4.item(0).getNodeValue());
		}
		catch (Exception e) {
			e.printStackTrace();
			LogTrace.writeLog(e.toString());
		}
	}

	private String getAirVacuum() {
		if (osaSetting.isAir()) {
			return "Air";
		}
		else {
			return "Vacuum";
		}
	}

	private String getPoutLoss() {
		return String.valueOf((int)(anaProp.getPoutLoss() * 10));
	}

	private String getPinLoss() {
		return String.valueOf((int)(anaProp.getPinLos() * 10));
	}

	private String getNfCal() {
		return String.valueOf((int)(anaProp.getK() * 1000));
	}

	private String getCutLevel() {
		return String.valueOf((int)(anaProp.getCutLevel() * 10));
	}

	private String getWavelengthDetectionType() {
		if (anaProp.isPeak()) {
			return "Peak";
		}
		else {
			return "Threshold";
		}
	}

	private String getSearchThreshold() {
		return String.valueOf((int)(anaProp.getPeakThreshold() * 10));
	}

	private String getSliceLevel() {
		return String.valueOf((int)(anaProp.getSliceLevel() * 10));
	}

	private String getActualResolutionMethod() {
		if (anaProp.getRbw().equals("Measured")) {
			return "Measured";
		}
		else {
			return "Initial";
		}
	}

	private String getNfSelect() {
		if (anaProp.getNfcalc().equals("Total")) {
			return "Total";
		}
		else {
			return "S-ASE";
		}
	}

	private String getFittingCurve() {
		if (anaProp.getFormula().equals("y=x(1) + x(2)*t")) {
			return "Linear";
		}
		else if (anaProp.getFormula().equals("y=x(1) + x(2)*t + x(3)*t^2")) {
			return "Gauss";
		}
		else if (anaProp.getFormula().equals("y=x(1) + x(2)*t + x(3)*t^2 + x(4)*t^3")) {
			return "3rd POLY";
		}
		else if (anaProp.getFormula().equals("y=x(1) + x(2)*t + x(3)*t^2 + x(4)*t^3 + x(5)*t^4")) {
			return "4th POLY";
		}
		else if (anaProp.getFormula().equals("y=x(1) + x(2)*t + x(3)*t^2 + x(4)*t^3 + x(5)*t^4 + x(6)*t^5")) {
			return "5th POLY";
		}
		return "Linear";
	}

	private String getMaskedSpan() {
		return String.valueOf((int)(anaProp.getMaskedSpan() * 100));
	}

	private String getFittingSpan() {
		return String.valueOf((int)(anaProp.getFittingSpan() * 100));
	}

	private String getFittingSpanMode() {
		if (anaProp.getSpanMethod().equals("Center")) {
			return "Auto (Center)";
		}
		else {
			return "Manual";
		}
	}

	private String getNoisePosition() {
		return String.valueOf((int)(anaProp.getFittingSpan() * 100));
	}

	private String getNoisePositionMode() {
		if (anaProp.getSpanMethod().equals("Center")) {
			return "Auto (Center)";
		}
		else {
			return "Manual";
		}
	}

	private String getAseDetectionType() {
		if (anaProp.isPoint()) {
			return "Point";
		}
		else {
			return "Area";
		}
	}

	private String getMethod() {
		if (anaProp.getMethod().equals("IEC")) {
			return "IEC";
		}
		else if (anaProp.getMethod().equals("Advanced")) {
			return "Advanced";
		}
		else {//if (anaProp.getMethod().equals("Off")) {
			return "Off";
		}
	}

	private String getSettingRes() {
		if (osaSetting.getSettingResolution() == 0.03) {
			return "0.03nm";
		}
		else if (osaSetting.getSettingResolution() == 0.05) {
			return "0.05nm";
		}
		else if (osaSetting.getSettingResolution() == 0.07) {
			return "0.07nm";
		}
		else if (osaSetting.getSettingResolution() == 0.1) {
			return "0.1nm";
		}
		else if (osaSetting.getSettingResolution() == 0.2) {
			return "0.2nm";
		}
		else if (osaSetting.getSettingResolution() == 0.5) {
			return "0.5nm";
		}
		else if (osaSetting.getSettingResolution() == 1.0) {
			return "1.0nm";
		}
		return "";
	}

	private String getSamplingPoints() {
		return String.valueOf(osaSetting.getSamplingPoints()) + "pt";
	}

	private String getActualRes() {
		return String.valueOf((int)(osaSetting.getActualResolution() * 1000));
	}

	private String getStop() {
		return String.valueOf((int)(osaSetting.getStopWavelength() * 100));
	}

	private String getStart() {
		return String.valueOf((int)(osaSetting.getStartWavelength() * 100));
	}

	private String getSpan() {
		return String.valueOf((int)(osaSetting.getSpanWavelength() * 100));
	}

	private String getCenter() {
		return String.valueOf((int)(osaSetting.getCenterWavelength() * 100));
	}

	private String getTraceBase64(int index) {
		if (traces.size() - 1 < index) {
			return "";
		}

		double[] trace = traces.get(index);

		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		DataOutputStream out = new DataOutputStream(bout);
		BASE64Encoder enc = new BASE64Encoder();
		String strRet = "";
    	try {

	        for (int i = 0; i < trace.length; i++) {	        	
	        	ByteArrayOutputStream tmpb = new ByteArrayOutputStream();
	        	DataOutputStream tmp = new DataOutputStream(tmpb);
				
	        	ByteBuffer bb = ByteBuffer.allocate(8);
	        	bb.putDouble(trace[i]*1000.0);
	        	tmp.write(bb.array());
				
				tmp.flush();
				byte[] arr = tmpb.toByteArray();
				byte tmpByte = arr[0];
				arr[0] = arr[7];
				arr[7] = tmpByte;
				tmpByte = arr[1];
				arr[1] = arr[6];
				arr[6] = tmpByte;
				tmpByte = arr[2];
				arr[2] = arr[5];
				arr[5] = tmpByte;
				tmpByte = arr[3];
				arr[3] = arr[4];
				arr[4] = tmpByte;

				strRet += enc.encode(arr);

	        }
	        out.flush();
		} catch (IOException e) {
			e.printStackTrace();
			LogTrace.writeLog(e.toString());
		}

		return strRet;//Base64.encodeBase64String(bout.toByteArray());
	}
}
